home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Libraries / TurboTCP 1.0.1 / TurboTCP.source / CTCPDriver.cp < prev    next >
Text File  |  1993-12-10  |  11KB  |  484 lines

  1. /*
  2. ** CTCPDriver.cp
  3. **
  4. **    TurboTCP support library
  5. **    TCP driver interface class
  6. **
  7. **    Copyright © 1993, FrostByte Design / Eric Scouten
  8. **
  9. */
  10.  
  11.  
  12. #define CTCPDriverNoGlobal                        // don’t redefine global vars
  13. #include "CTCPDriver.h"
  14.  
  15. #ifndef TurboTCPHeaders
  16.     #include <CApplication.h>
  17.     #include <CBartender.h>
  18.     #include <GetMyIPAddr.h>
  19.     #include <cast.h>
  20. #endif
  21.  
  22. #include <CDLOGDirector.h>
  23.  
  24. #include "CTCPApplication.h"
  25. #include "CTCPAsyncCall.h"
  26. #include "CTCPStream.h"
  27. #include "CTCPResolverCall.h"
  28.  
  29.  
  30. // resource definitions
  31.  
  32. #define DLOG_TCPDelayedQuit    23010
  33.  
  34.  
  35. // define global reference to the TCP driver object
  36.  
  37. extern CApplication    *gApplication;
  38. extern CBartender    *gBartender;
  39. CTCPDriver        *gTCPDriver;                    // not a class variable since it’s used
  40.                                             // so frequently throughout the application
  41.  
  42.  
  43. //    —— contruction/destruction ——
  44.  
  45. /*______________________________________________________________________
  46. **
  47. ** ITCPDriver
  48. **
  49. **    Clear the TCP driver object. Check to see if MacTCP is open. Optionally, opens TCP
  50. **    resolver.
  51. **
  52. **        doOpenResolver (Boolean):    TRUE to open TCP resolver as well
  53. **
  54. */
  55.  
  56. void CTCPDriver::ITCPDriver (Boolean doOpenResolver)
  57.  
  58. {
  59.  
  60.     // driver object must be locked, since it may be accessed during interupts
  61.     
  62.     MoveHHi((Handle) this);
  63.     this->Lock(TRUE);
  64.     
  65.     
  66.     // clear variables
  67.     
  68.     hasMacTCP = FALSE;
  69.     hasResolver = FALSE;
  70.     myTCPRefNum = 0;
  71.     myIPAddress = 0L;
  72.     gTCPDriver = this;
  73.     activeStreamList = NULL;
  74.     activeResolverList = NULL;
  75.     
  76.     
  77.     // clear asynch processing queue
  78.     
  79.     asyncQueue.qFlags = 0;
  80.     asyncQueue.qHead = NULL;
  81.     asyncQueue.qTail = NULL;
  82.  
  83.  
  84.     // create the active TCP/DNR call lists
  85.     
  86.     activeStreamList = new (CCluster);
  87.     activeStreamList->ICluster();
  88.     
  89.     activeResolverList = new (CCluster);
  90.     activeResolverList->ICluster();
  91.  
  92.  
  93.     // see if TCP & DNR are available
  94.     
  95.     CheckTCPDriver();
  96.     if (doOpenResolver)
  97.         CheckResolver();
  98.  
  99. }
  100.  
  101.  
  102. /*______________________________________________________________________
  103. **
  104. ** Dispose
  105. **
  106. **    Dispose of this object and any lingering TCP async call objects or TCP stream objects.
  107. **    It is CRITICAL that any lingering TCP streams be closed, released, and disposed;
  108. **    otherwise MacTCP is *guaranteed* to crash the machine when the next app launches.
  109. **    If the resolver is open, wait until all resolver queries have been cancelled.
  110. **
  111. **    If at least one second elapses between the start of this routine and the end, flash a
  112. **    dialog box to indicate the reason for the delay.
  113. **
  114. */
  115.  
  116. void CTCPDriver::Dispose (void)
  117.  
  118. {
  119.     register long    i;
  120.     CTCPStream    *theStream;
  121.     unsigned long    startTickCount;
  122.     unsigned long    theTime;
  123.     CDLOGDirector    *theDialog = NULL;
  124.  
  125.     
  126.     // cancel outstanding DNR calls & close resolver
  127.     
  128.     if (hasResolver)
  129.         CTCPResolverCall::CloseResolver();
  130.  
  131.  
  132.     // kill any lingering streams
  133.     
  134.     if (activeStreamList) {
  135.         for (i = 0; i < activeStreamList->numItems; i++) {
  136.             theStream = (CTCPStream*) (*(activeStreamList->items))[i];
  137.             theStream->PostponeDispose();
  138.         }
  139.     }
  140.  
  141.  
  142.     // wait for TCP to be done with everything
  143.     
  144.     GetDateTime(&startTickCount);
  145.     gBartender->DisableMenuBar();                    // disable all menus
  146.     
  147.     while (!activeStreamList->IsEmpty()) {
  148.  
  149.  
  150.         // do a private event loop & toss up a dialog if it takes more than 2 seconds
  151.         
  152.         GetDateTime(&theTime);
  153.         if ((theDialog == NULL) && (theTime - startTickCount >= 2)) {
  154.             theDialog = new (CDLOGDirector);
  155.             theDialog->IDLOGDirector(DLOG_TCPDelayedQuit, gApplication);
  156.             theDialog->BeginDialog();
  157.         }
  158.  
  159.                 
  160.         // wait for TCP completions & terminations
  161.         
  162.         gApplication->Process1Event();
  163.  
  164.     }
  165.     
  166.     
  167.     // get rid of dialog box (if there was one)
  168.     
  169.     ForgetObject(theDialog);
  170.  
  171.     
  172.     // dispose all the objects
  173.     
  174.     ForgetObject(activeStreamList);
  175.     ForgetObject(activeResolverList);
  176.     CObject::Dispose();
  177.  
  178. }
  179.  
  180.  
  181. //    —— event handling ——
  182.  
  183. /*______________________________________________________________________
  184. **
  185. ** ProcessNetEvents
  186. **
  187. **    Respond to all delayed TCP notifications, completions, disposals. This routine should be
  188. **    hooked into the application’s event loop or some very frequently called routine.
  189. **
  190. */
  191.  
  192. void CTCPDriver::ProcessNetEvents (void)
  193.  
  194. {
  195.     CObject            *theAsyncObject;
  196.     TurboTCPQElemPtr    theAsyncEntry;
  197.     CTCPAsyncCall        *theAsyncCall;
  198.     CTCPResolverCall    *theResolverCall;
  199.     CTCPStream        *theStream;
  200.     
  201.  
  202.     // respond to all the events in the TCP asynchronous events queue, if there are any
  203.  
  204.     while (asyncQueue.qHead) {
  205.     
  206.         // figure out what object caused the notification
  207.  
  208.         theAsyncEntry = (TurboTCPQElemPtr) asyncQueue.qHead;
  209.         theAsyncObject = theAsyncEntry->qSelfLink;
  210.  
  211.  
  212.         // remove it from the queue (just in case the event processing fails)
  213.         
  214.         Dequeue((QElemPtr) theAsyncEntry, &asyncQueue);
  215.         
  216.         
  217.         // process the event
  218.  
  219.         switch (theAsyncEntry->qType) {
  220.             case asyncCall:
  221.                 theAsyncCall = CheckedCast(theAsyncObject, CTCPAsyncCall);
  222.                 if (theAsyncCall)
  223.                     theAsyncCall ->ProcessCompletion();
  224.                 break;
  225.             case resolverCall:
  226.                 theResolverCall = CheckedCast(theAsyncObject, CTCPResolverCall);
  227.                 if (theResolverCall)
  228.                     theResolverCall->ProcessNotify();
  229.                 break;
  230.             case notifyStream:
  231.                 theStream = CheckedCast(theAsyncObject, CTCPStream);
  232.                 if (theStream)
  233.                     theStream->ProcessNotify();
  234.                 break;
  235.             case disposeStream:
  236.                 theStream = CheckedCast(theAsyncObject, CTCPStream);
  237.                 if (theStream)
  238.                     theStream->Dispose();
  239.                 break;
  240.  
  241.         }    // switch
  242.     }        // while
  243.  
  244. }
  245.  
  246.  
  247. //    —— ensure that TCP/DNR are present ——
  248.  
  249. /*______________________________________________________________________
  250. **
  251. ** CheckTCPDriver
  252. **
  253. **    Check to see if the MacTCP driver is present. Should be done before opening each new
  254. **    connection (built into CTCPStream). If TCP driver is present, updates the current IP address.
  255. **
  256. **        return (Boolean):    TRUE if MacTCP driver is present
  257. **
  258. */
  259.  
  260. Boolean CTCPDriver::CheckTCPDriver (void)
  261.  
  262. {
  263.     ParamBlockRec    theParamBlock;
  264.     unsigned char    theName[6] = "\p.IPP";        // MacTCP driver name
  265.  
  266.  
  267.     // if TCP not already confirmed, look for it
  268.     
  269.     if (!hasMacTCP) {
  270.         theParamBlock.ioParam.ioNamePtr = (StringPtr) &theName;
  271.         theParamBlock.ioParam.ioPermssn = fsCurPerm;
  272.         if ((short) PBOpenSync(&theParamBlock) == 0) {
  273.             myTCPRefNum = theParamBlock.ioParam.ioRefNum;
  274.             hasMacTCP = TRUE;
  275.         }
  276.     }
  277.  
  278.  
  279.     /*
  280.     **    If TCP driver available, get the IP address. This is done *each* time a new stream
  281.     **    is created because the address might have changed. (This could happen on a machine
  282.     **    connected by modem & SLIP, if the user hangs up the modem and re-dials the
  283.     **    SLIP server without quitting the program.)
  284.     */
  285.     
  286.     FetchIPAddr();
  287.     return (hasMacTCP);
  288.  
  289. }
  290.  
  291.  
  292. /*______________________________________________________________________
  293. **
  294. ** CheckResolver
  295. **
  296. **    Check to see if the MacTCP DNR code segment is available. If it isn’t, use the OpenResolver
  297. **    call to make it available.
  298. **
  299. **        return (Boolean):    TRUE if TCP resovler is present
  300. **
  301. */
  302.  
  303. Boolean CTCPDriver::CheckResolver (void)
  304.  
  305. {
  306.  
  307.     TRY {
  308.         CTCPResolverCall::OpenResolver();
  309.         hasResolver = TRUE;
  310.     }
  311.     CATCH {
  312.         hasResolver = FALSE;
  313.         NO_PROPAGATE;
  314.     }
  315.     ENDTRY;
  316.     return (hasResolver);
  317.  
  318. }
  319.  
  320.  
  321. //    —— get TCP driver numbers ——
  322.  
  323. /*______________________________________________________________________
  324. **
  325. ** GetTCPRefNum
  326. **
  327. **    Returns the Device Manager reference number for MacTCP, if available. Fails with
  328. **    “noTCPError” error if not available.
  329. **
  330. **        return (short):     MacTCP driver refnum
  331. **
  332. */
  333.  
  334. short CTCPDriver::GetTCPRefNum (void)
  335.  
  336. {
  337.     if (!hasMacTCP)
  338.         FailOSErr(noTCPError);
  339.     return (myTCPRefNum);
  340. }
  341.  
  342.  
  343. /*______________________________________________________________________
  344. **
  345. ** GetIPAddr
  346. **
  347. **    Returns the current local IP address, if available. Fails with “noTCPError” error if
  348. **    MacTCP is not installed.
  349. **
  350. **        return (ip_addr):     current IP address
  351. **
  352. */
  353.  
  354. ip_addr CTCPDriver::GetIPAddr (void)
  355.  
  356. {
  357.     if (!hasMacTCP)
  358.         FailOSErr(noTCPError);
  359.     return (myIPAddress);
  360. }
  361.  
  362.  
  363. /*______________________________________________________________________
  364. **
  365. ** FetchIPAddr (protected method)
  366. **
  367. **    Retrieve the local host’s IP address. Does nothing if MacTCP is not available. Stores the
  368. **    new address in the local field myIPAddress, which can be retrieved with the
  369. **    GetIPAddr() method.
  370. **
  371. */
  372.  
  373. void CTCPDriver::FetchIPAddr (void)
  374.  
  375. {
  376.     struct GetAddrParamBlock theIPParamBlock;
  377.  
  378.     myIPAddress = 0L;
  379.  
  380.     if (hasMacTCP) {
  381.         theIPParamBlock.csCode = ipctlGetAddr;
  382.         theIPParamBlock.ioCRefNum = myTCPRefNum;
  383.         PBControlSync((ParmBlkPtr) &theIPParamBlock);
  384.         if (theIPParamBlock.ioResult == noErr)
  385.             myIPAddress = theIPParamBlock.ourAddress;
  386.     }
  387. }
  388.  
  389.  
  390. //    —— postpone processing of interrupt-level notification ——
  391.  
  392. /*______________________________________________________________________
  393. **
  394. ** RegisterActiveStream
  395. **
  396. **    Add a TCP stream to the list of active TCP streams. The driver object uses this information
  397. **    to ensure that all streams are closed and terminated before the application quits.
  398. **
  399. **        theStream (CTCPStream *):    the stream to register
  400. **
  401. */
  402.  
  403. void CTCPDriver::RegisterActiveStream (CTCPStream *theStream)
  404.  
  405. {
  406.     activeStreamList->Add(theStream);
  407. }
  408.  
  409.  
  410. /*______________________________________________________________________
  411. **
  412. ** RegisterActiveResolver
  413. **
  414. **    Add a DNR resolver call to the list of active TCP streams. The driver object uses this
  415. **    information to ensure that all resolver calls are closed and terminated before the
  416. **    application quits.
  417. **
  418. **        theResolver (CTCPResolverCall *):    the resolver call to register
  419. **
  420. */
  421.  
  422. void CTCPDriver::RegisterActiveResolver (CTCPResolverCall *theResolver)
  423.  
  424. {
  425.     if (CheckResolverLimit())                        // disallow 9th DNR call
  426.         FailOSErr(resolverBusy);
  427.     activeResolverList->Add(theResolver);
  428. }
  429.  
  430.  
  431. /*______________________________________________________________________
  432. **
  433. ** RemoveActiveStream
  434. **
  435. **    Remove a TCP stream from the list of active TCP streams. This message indicates that
  436. **    MacTCP is no longer dependent on the memory structure for the stream.
  437. **
  438. **        theStream (CTCPStream *):    the stream to register
  439. **
  440. */
  441.  
  442. void CTCPDriver::RemoveActiveStream (CTCPStream *theStream)
  443.  
  444. {
  445.     if (activeStreamList)                        // just in case this is called during shutdown
  446.         activeStreamList->Remove(theStream);
  447. }
  448.  
  449.  
  450. /*______________________________________________________________________
  451. **
  452. ** RemoveActiveResolver
  453. **
  454. **    Remove a DNR resolver call from the list of active calls. This message indicates that
  455. **    the MacTCP DNR is no longer dependent on the memory structure for the call.
  456. **
  457. **        theResolver (CTCPResolverCall *):    the resolver call to register
  458. **
  459. */
  460.  
  461. void CTCPDriver::RemoveActiveResolver (CTCPResolverCall *theResolver)
  462.  
  463. {
  464.     if (activeResolverList)                        // just in case this is called during shutdown
  465.         activeResolverList->Remove(theResolver);
  466. }
  467.  
  468.  
  469. /*______________________________________________________________________
  470. **
  471. ** CheckResolverLimit
  472. **
  473. **    Test to see if the DNR is at its capacity for active calls (currently 8).
  474. **
  475. **        return (Boolean):    TRUE if no more DNR calls may be issued now
  476. **
  477. */
  478.  
  479. Boolean CTCPDriver::CheckResolverLimit (void)
  480.  
  481. {
  482.     return ((activeResolverList->numItems) >= maxResolverCalls);
  483. }
  484.